home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / mg / src.lzh / amiga / rexx.c < prev    next >
C/C++ Source or Header  |  1990-05-23  |  21KB  |  918 lines

  1. /*
  2.  * This file sends out and recieves REXX commands (well recieving them means
  3.  * we hand the off to excline, but...)
  4.  */
  5. #include "rexx.h"
  6.  
  7. #ifdef    REXX
  8.  
  9. #include <exec/types.h>
  10. #include <exec/ports.h>
  11. #include <rexx/storage.h>
  12. #include <rexx/rxslib.h>
  13. #ifdef LATTICE
  14. #include <proto/exec.h>
  15. #include <proto/intuition.h>
  16. #else
  17. #include <functions.h>
  18. #endif
  19.  
  20. #undef    TRUE
  21. #undef    FALSE
  22. #include "def.h"
  23. #include "line.h"
  24. #include "buffer.h"
  25. #include "window.h"
  26. #include "macro.h"
  27. #include "region.h"
  28.  
  29. #ifdef    ANSI
  30. #undef    EOF            /* Strange..., but stdio complains about it */
  31. #include <stdio.h>        /* Only if we've got sprintf in here */
  32. #include <stdlib.h>
  33. #include <fcntl.h>
  34. #undef    HUGE            /* Collides with math.h */
  35. #include <math.h>
  36. #include <string.h>
  37. #endif
  38.  
  39. /*
  40.  * The pointer to the Rexx library, which we really want when dealing with
  41.  * Rexx, and some return value for messages.
  42.  */
  43. struct Library *RexxSysBase;
  44. #define    FAIL_LOCKED    3
  45. #define FAIL_NOREXX    4
  46.  
  47. /*
  48.  * My static functions.
  49.  */
  50. static int rexxdocommand PROTO((char *, long));
  51. static int getrexxargs PROTO((struct RexxMsg *, int));
  52. static int rexxread PROTO((int));
  53. static int rexxstemint PROTO((char *, int, int));
  54. static int rexxstemstring PROTO((char *, int, char *, int));
  55. static int findline PROTO((struct line *));
  56. static struct MsgPort *lockport PROTO((char *));
  57. static int spinport PROTO((struct MsgPort *));
  58.  
  59. #ifdef    LATTICE
  60. long __stdargs SetRexxVar PROTO((struct RexxMsg *, char *, char *, long)) ;
  61. #else
  62. long SetRexxVar PROTO((struct RexxMsg *, char *, char *, long)) ;
  63. static char *strupr PROTO((char *));
  64. #endif
  65.  
  66. struct RexxArg *CreateArgstring PROTO((char *, long)) ;
  67. long LengthArgstring PROTO((struct RexxArg *)) ;
  68. void DeleteArgstring PROTO((struct RexxArg *)) ;
  69. struct RexxMsg *CreateRexxMsg PROTO((struct MsgPort *, char *, char *)) ;
  70. void ClearRexxMsg PROTO((struct RexxMsg *, long)) ;
  71. void DeleteRexxMsg PROTO((struct RexxMsg *)) ;
  72.  
  73. /*
  74.  * Pointer to rexx macro to run on exit.
  75.  */
  76. static char    *RexxExitCmd;
  77.  
  78. /*
  79.  * Commands that return results can only do so if the RexxMsg that caused
  80.  * them to be executed is willing to take results. To make this test easy,
  81.  * the RexxMsg is stored in CurrentMsg between it's being recieved and
  82.  * sending out the reply. Any other time, it will be NULL, and the Rexx
  83.  * command check for that if they shouldn't be executed unless there is a
  84.  * RexxMsg active. In addition, rexxlock needs to reply to this message
  85.  * indicating that the lock succeeded before going into locked mode, so it
  86.  * needs access to CurrentMsg. Result strings get passed from rexx commands
  87.  * back to the script - and the other way, in the case of rexxdoregion - via
  88.  * RexxResult. It's normally NULL, unless the executed command set a result,
  89.  * or a macro that we were still locked to on exit returned a result. In
  90.  * which case, it points to the RexxArgstring for the result. The consumer is
  91.  * responsible for deleting it, and the producer is responsible for creating
  92.  * it.
  93.  * 
  94.  */
  95. static struct RexxMsg *CurrentMsg = NULL;
  96. static struct RexxArg *RexxResult = NULL;
  97.  
  98. /*
  99.  * Things for dealing with asynch REXX messages. rexxport is the port that
  100.  * those messages come in on, and it's name is mgname. Since rexxport must be
  101.  * checked for messages in the event loop, it's not static. RepliesNeeded is
  102.  * the number of reply messages we need to see on rexxport. Lockadd is the
  103.  * address of the port name that a given macro is locked to, or NULL if we're
  104.  * not locked. ADDSIZE is the size of the port name we use for dynamically
  105.  * allocated ports
  106.  */
  107. struct MsgPort *rexxport = NULL;
  108. static char     mgname[5] = "mg\0\0";
  109. static unsigned RepliesNeeded = 0;
  110. static char    *lockadd = NULL;
  111. #define ADDSIZE    8
  112.  
  113. /*
  114.  * This routine dispatches any REXX messages coming in. However, to allow for
  115.  * REXX commands that start other REXX commands, we must save and restore the
  116.  * environment (CurrentMsg).
  117.  */
  118. int
  119. disprexx(inport)
  120.     struct MsgPort *inport;
  121. {
  122.     register int    s, t;
  123.     register struct RexxMsg *savemsg;
  124.  
  125.     savemsg = CurrentMsg;
  126.  
  127.     for (;;) {
  128.         RexxResult = NULL;
  129.         /* Check for commands */
  130.         if (inport && (CurrentMsg = (struct RexxMsg *) GetMsg(inport))) {
  131.             if (CurrentMsg->rm_Node.mn_Node.ln_Type != NT_REPLYMSG)
  132.                 s = excline(ARG0(CurrentMsg),
  133.                     LengthArgstring((struct RexxArg *) ARG0(CurrentMsg)));
  134.         }
  135.         /* And then for replies or asynch commands */
  136.         else if (CurrentMsg = (struct RexxMsg *) GetMsg(rexxport)) {
  137.             if (CurrentMsg->rm_Node.mn_Node.ln_Type != NT_REPLYMSG)
  138.                 if (!inport)
  139.                     s = FAIL_NOREXX;
  140.                 else if (lockadd)
  141.                     s = FAIL_LOCKED;
  142.                 else
  143.                     s = excline(ARG0(CurrentMsg),
  144.                         LengthArgstring((struct RexxArg *) ARG0(CurrentMsg)));
  145.         }
  146.         if (CurrentMsg == NULL)
  147.             break;
  148.         if (CurrentMsg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG) {
  149.             RepliesNeeded -= 1;
  150.             s = CurrentMsg->rm_Result1 < 2
  151.                 ? 1 - CurrentMsg->rm_Result1
  152.                 : ABORT;
  153.             t = ((char *)CurrentMsg->rm_CommAddr == lockadd);
  154.             if (s == TRUE && (CurrentMsg->rm_Action & RXFF_RESULT)
  155.                 && CurrentMsg->rm_Result2 != NULL)
  156.                 /* Aha - a result. Deal with it. */
  157.                 if (t)
  158.                     RexxResult = (struct RexxArg *) CurrentMsg->rm_Result2;
  159.                 else
  160.                     DeleteArgstring((struct RexxArg *)
  161.                             CurrentMsg->rm_Result2);
  162.             /* Free the memory for this message */
  163.             FreeMem(CurrentMsg->rm_CommAddr, ADDSIZE);
  164.             ClearRexxMsg(CurrentMsg, 16);
  165.             DeleteRexxMsg(CurrentMsg);
  166.             if (!t)
  167.                 continue;
  168.             CurrentMsg = savemsg;
  169.             lockadd = NULL;
  170.             return s;
  171.         }
  172.         if (s < 2)
  173.             s = 1 - s;
  174.         CurrentMsg->rm_Result1 = s;
  175.         CurrentMsg->rm_Result2 = (RexxResult != NULL)
  176.             ? (LONG) RexxResult
  177.             : 0L;
  178.         ReplyMsg((struct Message *) CurrentMsg);
  179.     }
  180.     CurrentMsg = savemsg;
  181.     return -1;
  182. }
  183.  
  184. void
  185. openrexx()
  186. {
  187.     register short  i, j;
  188.  
  189.     if ((RexxSysBase = OpenLibrary(RXSNAME, 0)) == NULL)
  190.         return;
  191.     srand((unsigned) &lockadd);    /* Just to make things change */
  192.     for (i = 33; i < 127; i++) {
  193.         for (j = 33; j < 127; j++) {
  194.             Forbid();
  195.             if (FindPort(mgname) == NULL)
  196.                 rexxport = CreatePort(mgname, 0L);
  197.             Permit();
  198.             if (rexxport != NULL)
  199.                 return;
  200.             mgname[2] = j;
  201.         }
  202.         mgname[3] = i;
  203.     }
  204.  
  205.     /* No port opened, so we don't do Rexx, so we close RexxSysBase */
  206.     CloseLibrary(RexxSysBase);
  207.     RexxSysBase = NULL;
  208. }
  209.  
  210. void
  211. closerexx()
  212. {
  213.  
  214.     if (!RexxSysBase)
  215.         return;        /* No Rexx to close */
  216.     if (RexxExitCmd != NULL)
  217.         rexxdocommand(RexxExitCmd, RXCOMM);
  218.     if (rexxport) {
  219.         while (RepliesNeeded) {
  220.             WaitPort(rexxport);
  221.             disprexx(NULL);
  222.         }
  223.         DeletePort(rexxport);
  224.     }
  225.     CloseLibrary(RexxSysBase);
  226. }
  227. /*
  228.  * Commands that make Rexx macros execute.
  229.  */
  230.  
  231. rexxexitcommand(f, n)
  232. {
  233.     int             s;
  234.     static char     exitcom[NLINE];
  235.  
  236.     if (!RexxSysBase)
  237.         return FALSE;
  238.     if ((s = ereply("REXX command to run on exit: ", exitcom, NLINE)) != TRUE)
  239.         return s;
  240.     RexxExitCmd = exitcom;
  241.     return TRUE;
  242. }
  243.  
  244. rexxcommand(f, n)
  245. {
  246.     int             s;
  247.     char            cmd[NLINE];
  248.  
  249.     if (!RexxSysBase)
  250.         return FALSE;
  251.     if ((s = ereply("REXX command: ", cmd, NLINE)) != TRUE)
  252.         return s;
  253.  
  254.     return rexxdocommand(cmd, f & FFUNIV ? RXCOMM | RXFF_TOKEN : RXCOMM);
  255. }
  256.  
  257. rexxcomregion(f, n)
  258.     int             f, n;
  259. {
  260.     char           *out;
  261.     register RSIZE  length, size;
  262.     register struct line *lp;
  263.     int             status, insertres;
  264.     char           *string;
  265.     struct region   reg;
  266.  
  267.     if (!RexxSysBase)
  268.         return FALSE;
  269.     if ((length = getregion(®)) != TRUE)
  270.         return length;
  271.     size = reg.r_size;
  272.  
  273.     if ((out = malloc(size + 1)) == NULL) {
  274.         ewprintf("Can't get %d bytes", size + 1);
  275.         return FALSE;
  276.     }
  277.     string = out;        /* Save the start of the thing... */
  278.  
  279.     /* Copy the region to out */
  280.     lp = reg.r_linep;
  281.     length = llength(lp) - reg.r_offset;
  282.     bcopy(<ext(lp)[reg.r_offset], out, length);
  283.     size -= length;
  284.     out += length;
  285.  
  286.     while (size > 0) {
  287.         /* Add a newline to the output string */
  288.         *out++ = '\n';
  289.         size -= 1;
  290.  
  291.         /* Add part/all of the current line to the output string */
  292.         lp = lforw(lp);
  293.         length = llength(lp);
  294.         if (length > size)
  295.             length = size;
  296.         bcopy(ltext(lp), out, length);
  297.         out += length;
  298.         size -= length;
  299.     }
  300.     *out = '\0';
  301.  
  302.     /* Figure out how many arguments we really have */
  303.     insertres = (n <= 0);
  304.     if ((f & FFARG) == 0)
  305.         n = 0;
  306.     else if (insertres)
  307.         n = -n;
  308.     if (n > MAXRMARG) {
  309.         ewprintf("Can only have %d args for rexx commands", MAXRMARG);
  310.         n = MAXRMARG;
  311.     }
  312.     status = rexxdocommand(string, RXFUNC | RXFF_RESULT | RXFF_STRING | n);
  313.  
  314.     /* Deal with result string if we've got one */
  315.     if (status == TRUE && RexxResult != NULL) {
  316.         if (insertres)
  317.             sinsert((char *) RexxResult);
  318.         else
  319.             ewprintf("Result was: %s", (char *) RexxResult);
  320.         DeleteArgstring(RexxResult);
  321.     }
  322.     RexxResult = NULL;
  323.     return status;
  324. }
  325. /*
  326.  * rexxgetargs - get N args from the user, returning ABORT if they abort,
  327.  * etc.
  328.  */
  329. int
  330. getrexxargs(msg, n)
  331.     struct RexxMsg *msg;
  332.     int             n;
  333. {
  334.     register int    count, status = TRUE;
  335.     char            arg[NLINE];
  336.  
  337.     for (count = 1; count <= n; count += 1) {
  338.         if ((status = ereply("Arg #%d? ", arg, NLINE, count)) != TRUE
  339.             || (msg->rm_Args[count] =
  340.             (STRPTR) CreateArgstring(arg, strlen(arg))) == NULL)
  341.             break;
  342.     }
  343.     return status;
  344. }
  345.  
  346. /*
  347.  * Finish filling in the msg, send the message to Rexx, and then call
  348.  * spinport to get the work done. We get here from commands that can be
  349.  * issued by macros, so we can be run when locked. So we have to save lockadd
  350.  * upon entry, and restore it before we exit.
  351.  */
  352. static
  353. rexxdocommand(command, action)
  354.     char           *command;
  355.     long            action;
  356. {
  357.     register struct RexxMsg *out = NULL;
  358.     struct MsgPort *macport = NULL, *rexx;
  359.     int             s;
  360.     char           *savelock;
  361.  
  362.     if (rexxport == NULL)
  363.         return FALSE;
  364.     savelock = lockadd;
  365.     if ((lockadd = AllocMem(ADDSIZE, 0L)) == NULL) {
  366.         ewprintf("Can't get %d bytes", ADDSIZE);
  367.         goto error;
  368.     }
  369.     if ((macport = lockport(lockadd)) == NULL)
  370.         goto error;
  371.     if ((out = CreateRexxMsg(rexxport, "mg", lockadd)) == NULL
  372.         || (out->rm_Args[0] = (STRPTR) CreateArgstring(command, strlen(command))) == NULL
  373.         || ((action & RXFUNC) && (s = getrexxargs(out, action & 0xF)) != TRUE))
  374.         goto error;
  375.     out->rm_Action = action;
  376.  
  377.     Forbid();
  378.     rexx = FindPort("REXX");
  379.     if (rexx)
  380.         PutMsg(rexx, (struct Message *) out);
  381.     Permit();
  382.     if (!rexx) {
  383.         s = FALSE;
  384.         goto error;
  385.     }
  386.     RepliesNeeded += 1;
  387.  
  388.     /* Spin until macro finishes, or unlocked */
  389.     s = spinport(macport);
  390.     lockadd = savelock;
  391.     return s;
  392.  
  393.     /* Something died, so clean up and tell the use about it */
  394. error:
  395.     if (lockadd)
  396.         FreeMem(lockadd, ADDSIZE);
  397.     if (macport)
  398.         DeletePort(macport);
  399.     if (out) {
  400.         ClearRexxMsg(out, 16);
  401.         DeleteRexxMsg(out);
  402.     }
  403.     lockadd = savelock;
  404.     return s;
  405. }
  406.  
  407. /*
  408.  * Set lockadd to the name of a public port, and return the address of the
  409.  * port.
  410.  */
  411. static struct MsgPort *
  412. lockport(portname)
  413.     char           *portname;
  414. {
  415.     struct MsgPort *port = NULL;
  416.  
  417.     while (port == NULL) {
  418.         sprintf(portname, "mg_%04d", rand() % 10000);
  419.         Forbid();
  420.         if (FindPort(portname) == NULL)
  421.             port = CreatePort(portname, 0L);
  422.         Permit();
  423.     }
  424.     return port;
  425. }
  426.  
  427. /*
  428.  * Spin on the port we got passed until either rexxunlock is called, or until
  429.  * we get a reply message for the macro we started. In the fomer case, return
  430.  * true; in the latter, return the value the macro returned.
  431.  */
  432. static int
  433. spinport(port)
  434.     struct MsgPort *port;
  435. {
  436.     register int    s;
  437.     register int    sigbits;
  438.  
  439.     sigbits = (1l << rexxport->mp_SigBit) | (1L << port->mp_SigBit);
  440.     do {
  441.         Wait(sigbits);
  442.     } while ((s = disprexx(port)) < 0 && lockadd);
  443.  
  444.     DeletePort(port);
  445.     if (lockadd)
  446.         rexxunlock(FFRAND, 1);
  447.     else
  448.         s = TRUE;
  449.     return s;
  450. }
  451.  
  452. /*
  453.  * rexx locking & unlocking functions. Rexxlock creates a new port for the
  454.  * macro we're locking, and calls spinport on that port. Rexxunlock just
  455.  * toggles the global lockadd to indicate we're not locked. Both return the
  456.  * public port name that will now accept messages to the invoking rexx
  457.  * program.
  458.  */
  459. rexxlock(f, n)
  460.     int             f, n;
  461. {
  462.     struct MsgPort *port;
  463.     char            lockname[ADDSIZE];
  464.  
  465.     /* Make sure we got called properly */
  466.     if (!CurrentMsg || lockadd || !(CurrentMsg->rm_Action & RXFF_RESULT))
  467.         return FALSE;
  468.  
  469.     if ((port = lockport(lockname)) == NULL)
  470.         return FALSE;
  471.  
  472.     CurrentMsg->rm_Result1 = 0;
  473.     lockadd = (char *) CreateArgstring(lockname, strlen(lockname));
  474.     CurrentMsg->rm_Result2 = (long) lockadd;
  475.     ReplyMsg((struct Message *) CurrentMsg);
  476.  
  477.     /* Tun off the reply to this message in disprexx */
  478.     CurrentMsg = NULL;
  479.     return spinport(port);
  480. }
  481.  
  482. rexxunlock(f, n)
  483.     int             f, n;
  484. {
  485.  
  486.     lockadd = NULL;
  487.     if (!(f & FFRAND) && CurrentMsg && CurrentMsg->rm_Action & RXFF_RESULT)
  488.         RexxResult = CreateArgstring(mgname, strlen(mgname));
  489.     return TRUE;
  490. }
  491. /*
  492.  * rexx echo line functions.
  493.  */
  494. rexxdisplay(f, n)
  495.     int             f, n;
  496. {
  497.     struct macro   *save;
  498.     char            buf[NLINE];
  499.  
  500.     if (!CurrentMsg)
  501.         return FALSE;
  502.     eread("", buf, NLINE, 0);
  503.     save = inmacro;
  504.     inmacro = NULL;
  505.     ewprintf("%s", buf);
  506.     inmacro = save;
  507.     return TRUE;
  508. }
  509.  
  510. rexxrequest(f, n)
  511.     int             f, n;
  512. {
  513.  
  514.     return rexxread(EFNEW);
  515. }
  516.  
  517. rexxreqbuf(f, n)
  518.     int             f, n;
  519. {
  520.  
  521.     return rexxread(EFNEW | EFBUF);
  522. }
  523.  
  524. rexxreqfunc(f, n)
  525.     int             f, n;
  526. {
  527.  
  528.     return rexxread(EFNEW | EFFUNC);
  529. }
  530.  
  531. rexxreqmacro(f, n)
  532.     int             f, n;
  533. {
  534.  
  535.     return rexxread(EFNEW | EFMACRO);
  536. }
  537.  
  538. static
  539. rexxread(flag)
  540. {
  541.     char            buf[NLINE], inbuf[NLINE];
  542.     struct macro   *save;
  543.     int             status;
  544.  
  545.     if (!CurrentMsg)
  546.         return FALSE;
  547.     eread("", buf, NLINE, 0);
  548.     save = inmacro;
  549.     inmacro = NULL;
  550.     if ((status = eread("%s", inbuf, NLINE, flag, buf)) == TRUE
  551.         && (CurrentMsg->rm_Action & RXFF_RESULT))
  552.         RexxResult = CreateArgstring(inbuf, strlen(inbuf));
  553.     inmacro = save;
  554.     return status;
  555. }
  556. /*
  557.  * Misc. rexx functions.
  558.  */
  559. rexxinsert(f, n)
  560.     int             f, n;
  561. {
  562.     KCHAR        c;
  563.  
  564.     if (!CurrentMsg)
  565.         return FALSE;
  566.     c = getkey(SEESCR);
  567.     while (c != SOFTCR) {
  568.         if (((c == '\n') ? lnewline() : linsert(1, c)) != TRUE)
  569.             return FALSE;
  570.         c = getkey(SEESCR);
  571.         }
  572.     return TRUE;
  573. }
  574.  
  575. rexxline(f, n)
  576.     int             f, n;
  577. {
  578.     register struct line *clp;
  579.  
  580.     if ((CurrentMsg->rm_Action & RXFF_RESULT) == 0)
  581.         return TRUE;
  582.     if ((f & FFARG) == 0)
  583.         clp = curwp->w_dotp;
  584.     else if (n > 0) {
  585.         clp = lforw(curbp->b_linep);    /* "clp" is first line     */
  586.         while (--n > 0) {
  587.             if (lforw(clp) == curbp->b_linep)
  588.                 return FALSE;
  589.             clp = lforw(clp);
  590.         }
  591.     } else {
  592.         clp = lback(curbp->b_linep);    /* clp is last line */
  593.         while (n < 0) {
  594.             if (lback(clp) == curbp->b_linep)
  595.                 return FALSE;
  596.             clp = lback(clp);
  597.             n++;
  598.         }
  599.     }
  600.     RexxResult = CreateArgstring(ltext(clp), llength(clp));
  601.     return TRUE;
  602. }
  603.  
  604. /*
  605.  * A pair of tools for manipulating the window we use.
  606.  */
  607. rexxwait(f, n)
  608.     int             f, n;
  609. {
  610.  
  611.     if (!RexxSysBase)
  612.         return FALSE;
  613.     tthide(FALSE);
  614.     WaitPort(rexxport);
  615.     ttshow(FALSE);
  616.     /* Go run the command and update the screen */
  617.     disprexx(rexxport);
  618.     update();
  619.     return TRUE;
  620. }
  621.  
  622. rexxtopwindow(f, n)
  623.     int             f, n;
  624. {
  625.     extern struct Window *EmW;
  626.  
  627.     WindowToFront(EmW);
  628.     return TRUE;
  629. }
  630.  
  631. /*
  632.  * rexx stem-variable functions.
  633.  */
  634. rexxwindow(f, n)
  635.     int             f, n;
  636. {
  637.     char            stem[NLINE];
  638.     register int    count;
  639.  
  640.     if (!CurrentMsg)
  641.         return FALSE;
  642.     eread("", stem, NLINE, 0);
  643.  
  644.     /* Upcase the variable name: required by the interface */
  645.     strupr(stem);
  646.  
  647.     /* Window Dimensions */
  648.     if (rexxstemint(stem, 1, curwp->w_ntrows) == FALSE)
  649.         count = 0;
  650.     else if (rexxstemint(stem, 2, ncol) == FALSE)
  651.         count = 1;
  652.     else if (rexxstemint(stem, 3, findline(curwp->w_linep)) == FALSE)
  653.         count = 2;
  654.     else if (curwp->w_bufp == NULL || curwp->w_bufp->b_bname == NULL
  655.         || rexxstemstring(stem, 4, curwp->w_bufp->b_bname, -1) == FALSE)
  656.         count = 3;
  657.     else if (rexxstemstring(stem, 5, curwp->w_bufp->b_fname, -1) == FALSE)
  658.         count = 4;
  659.     else
  660.         count = 5;    /* Did them ALL! */
  661.  
  662.     rexxstemint(stem, 0, count);
  663.     return count == 5;
  664. }
  665.  
  666. rexxpoint(f, n)
  667.     int             f, n;
  668. {
  669.     char            stem[NLINE];
  670.     register int    count;
  671.  
  672.     if (!CurrentMsg)
  673.         return FALSE;
  674.     eread("", stem, NLINE, 0);
  675.  
  676.     /* Upcase the variable name: required by the interface */
  677.     strupr(stem);
  678.  
  679.     if (rexxstemint(stem, 1, findline(curwp->w_dotp)) == FALSE)
  680.         count = 0;
  681.     else if (rexxstemint(stem, 2, curwp->w_doto + 1) == FALSE)
  682.         count = 1;
  683.     else if (rexxstemstring(stem, 3, ltext(curwp->w_dotp), llength(curwp->w_dotp)) == FALSE)
  684.         count = 2;
  685.     else
  686.         count = 3;
  687.  
  688.     rexxstemint(stem, 0, count);
  689.     return count == 3;
  690. }
  691.  
  692. rexxmark(f, n)
  693.     int             f, n;
  694. {
  695.     char            stem[NLINE];
  696.     register int    count;
  697.  
  698.     if (!CurrentMsg)
  699.         return FALSE;
  700.     eread("", stem, NLINE, 0);
  701.  
  702.     if (curwp->w_markp == NULL) {    /* No mark */
  703.         rexxstemint(stem, 0, 0);
  704.         return FALSE;
  705.     }
  706.     /* Upcase the variable name: required by the interface */
  707.     strupr(stem);
  708.  
  709.     if (rexxstemint(stem, 1, findline(curwp->w_markp)) == FALSE)
  710.         count = 0;
  711.     else if (rexxstemint(stem, 2, curwp->w_marko + 1) == FALSE)
  712.         count = 1;
  713.     else if (rexxstemstring(stem, 3, ltext(curwp->w_markp), llength(curwp->w_markp)) == FALSE)
  714.         count = 2;
  715.     else
  716.         count = 3;
  717.  
  718.     rexxstemint(stem, 0, count);
  719.     return count == 3;
  720. }
  721.  
  722. rexxbuffer(f, n)
  723.     int             f, n;
  724. {
  725.     char            stem[NLINE];
  726.     register int    count;
  727.     register RSIZE  chars, lines;
  728.     RSIZE           mark, point;
  729.     register struct line *clp;
  730.  
  731.     if (!CurrentMsg)
  732.         return FALSE;
  733.     eread("", stem, NLINE, 0);
  734.  
  735.     /* Upcase the variable name: required by the interface */
  736.     strupr(stem);
  737.  
  738.     /* Find the line & dot numbers */
  739.     clp = lforw(curbp->b_linep);
  740.     mark = point = chars = 0;
  741.     for (lines = 1;; lines += 1) {
  742.         chars += llength(clp);
  743.         if (clp == curwp->w_dotp)
  744.             point = lines;
  745.         if (clp == curwp->w_markp)
  746.             mark = lines;
  747.         if ((clp = lforw(clp)) == curbp->b_linep)
  748.             break;
  749.         chars += 1;    /* Newline, if present */
  750.     }
  751.  
  752.     if (curbp->b_bname == NULL
  753.         || rexxstemstring(stem, 1, curbp->b_bname, -1) == FALSE)
  754.         count = 0;
  755.     else if (rexxstemstring(stem, 2, curbp->b_fname, -1) == FALSE)
  756.         count = 1;
  757.     else if (rexxstemint(stem, 3, lines) == FALSE)
  758.         count = 2;
  759.     else if (rexxstemint(stem, 4, chars) == FALSE)
  760.         count = 3;
  761.     else if (rexxstemint(stem, 5, point) == FALSE)
  762.         count = 4;
  763.     else if (mark == 0 || rexxstemint(stem, 6, mark) == FALSE)
  764.         count = 5;
  765.     else
  766.         count = 6;
  767.  
  768.     rexxstemint(stem, 0, count);
  769.     return count == 6;
  770. }
  771.  
  772. rexxbuflist(f, n)
  773.     int             f, n;
  774. {
  775.     char            stem[NLINE], var[NLINE + 10], value[NLINE];
  776.     register int    count;
  777.     register struct buffer *bp;
  778.  
  779.     if (!CurrentMsg)
  780.         return FALSE;
  781.     eread("", stem, NLINE, 0);
  782.  
  783.     /* Upcase the variable name: required by the interface */
  784.     strupr(stem);
  785.  
  786.     for (count = 1, bp = bheadp; bp; bp = bp->b_bufp, count += 1) {
  787.         if (bp->b_bname == NULL)
  788.             break;
  789.         sprintf(var, "%s.%d.NAME", stem, count);
  790.         strcpy(value, bp->b_bname);
  791.         if (SetRexxVar(CurrentMsg, var, value, strlen(value)))
  792.             break;
  793.         sprintf(var, "%s.%d.FILE", stem, count);
  794.         strcpy(value, bp->b_fname);
  795.         if (SetRexxVar(CurrentMsg, var, value, strlen(value)))
  796.             break;
  797.         sprintf(var, "%s.%d.STATUS", stem, count);
  798.         value[0] = '\0';
  799.         if (bp->b_flag & BFCHG)
  800.             strcat(value, "CHANGED ");
  801.         if (bp == curbp)
  802.             strcat(value, "CURRENT");
  803.         if (SetRexxVar(CurrentMsg, var, value, strlen(value)))
  804.             break;
  805.     }
  806.  
  807.     rexxstemint(stem, 0, count - 1);
  808.     return bp == NULL;
  809. }
  810.  
  811. rexxregion(f, n)
  812.     int             f, n;
  813. {
  814.     register struct line *lp;
  815.     register RSIZE  count, length;
  816.     char            stem[NLINE], out[NLINE + 2];
  817.     struct region   reg;
  818.  
  819.     if (!CurrentMsg)
  820.         return FALSE;
  821.     eread("", stem, NLINE, 0);
  822.     strupr(stem);
  823.  
  824.     if ((count = getregion(®)) != TRUE) {
  825.         rexxstemint(stem, 0, 0);
  826.         return count;
  827.     }
  828.     lp = reg.r_linep;
  829.  
  830.     /* Set up end of first line */
  831.     length = llength(lp) - reg.r_offset;
  832.     bcopy(<ext(lp)[reg.r_offset], out, length);
  833.     count = 1;
  834.  
  835.     while (reg.r_size > length) {
  836.         out[length] = '\n';
  837.         if (rexxstemstring(stem, count, out, length + 1) == FALSE)
  838.             reg.r_size = -1;
  839.         else {
  840.             reg.r_size -= length + 1;
  841.             count += 1;
  842.             lp = lforw(lp);
  843.             length = llength(lp);
  844.             bcopy(ltext(lp), out, length);
  845.         }
  846.     }
  847.  
  848.     /* Now, if needed, do head of last line */
  849.     if (reg.r_size <= 0)
  850.         count -= 1;
  851.     else if (rexxstemstring(stem, count, out, reg.r_size) == FALSE) {
  852.         reg.r_size = -1;
  853.         count -= 1;
  854.     }
  855.     rexxstemint(stem, 0, count);
  856.     return reg.r_size != -1;
  857. }
  858.  
  859. static int
  860. rexxstemint(stem, count, in)
  861.     char           *stem;
  862.     int             count, in;
  863. {
  864.     char            var[NLINE + 2], value[NLINE];
  865.  
  866.     sprintf(var, "%s.%d", stem, count);
  867.     sprintf(value, "%d", in);
  868.     return SetRexxVar(CurrentMsg, var, value, strlen(value)) == 0;
  869. }
  870.  
  871. static int
  872. rexxstemstring(stem, count, value, length)
  873.     char           *stem;
  874.     int             count;
  875.     char           *value;
  876.     int             length;
  877. {
  878.     char            var[NLINE + 2];
  879.  
  880.     sprintf(var, "%s.%d", stem, count);
  881.     if (length < 0)
  882.         length = strlen(value);
  883.     return SetRexxVar(CurrentMsg, var, value, length) == 0;
  884. }
  885.  
  886. static int
  887. findline(lp)
  888.     struct line    *lp;
  889. {
  890.     register struct line *slp;
  891.     register int    count;
  892.  
  893.     for (slp = curbp->b_linep, count = 0;
  894.          slp != lp;
  895.          slp = lforw(slp), count += 1);
  896.     return count;
  897. }
  898.  
  899. #ifndef LATTICE
  900. static char *
  901. strupr(s)
  902.     char *s;
  903. {
  904.     char *c;
  905.     extern char toupper();
  906.  
  907.     c=s;
  908.     while(*s) {
  909.         *s = toupper(*s);
  910.             s++;
  911.     }
  912.     return(c);
  913. }
  914. #endif
  915. #else
  916. #include "nullfile.h"
  917. #endif
  918.